﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using GC_FFW.BusinessEntities.Abstractions.Interfaces.Soccerfame;
using GC_FFW.BusinessEntities.Soccerfame;
using GC_FFW.Common.Constants.HTML;
using GC_FFW.SoccerfameParser.Abstractions.Interfaces.Helpers;
using GC_FFW.SoccerfameParser.Abstractions.Managers;
using HtmlAgilityPack;

namespace GC_FFW.SoccerfameParser.Managers
{
	public class HtmlDocumentManager : HtmlDocumentBaseManager
	{
		#region Constructors

		public HtmlDocumentManager(WebPageBaseManager webPageManager, IStringManager stringManager)
			: base(webPageManager, stringManager) { }

		#endregion

		#region Base Class Members

		public override HtmlDocument CreateHtmlDocument(string url)
		{
			var document = new HtmlDocument();
			var documentMarkup = WebPageManager.GetWebPageHtmlMarkup(url);
			document.LoadHtml(documentMarkup);
			return document;
		}

		public override IHyperlink GetHyperlink(HtmlNode htmlNode)
		{
			if (htmlNode == null || htmlNode.Name != TagNames.ANCHOR)
				return null;

			return new Hyperlink
			{
				Url = htmlNode.Attributes[TagAttributes.HREF] != null
					? htmlNode.Attributes[TagAttributes.HREF].Value
					: string.Empty,
				Name = GetFullInnerTextString(htmlNode)
			};
		}

		public override string GetFullInnerTextString(HtmlNode htmlNode)
		{
			if (htmlNode == null) return string.Empty;

			var result = new StringBuilder();

			foreach (var childNode in htmlNode.ChildNodes)
			{
				result.Append(HttpUtility.HtmlDecode(childNode.InnerText.Trim()));
			}

			return HttpUtility.HtmlDecode(result.ToString().Trim());
		}

		public override IEnumerable<HtmlNode> FindNodesByPartId(HtmlNode htmlNode, string partId)
		{
			if (htmlNode == null) return null;

			var result = new List<HtmlNode>();

			ReqursiveScanNodesByPartId(htmlNode.ChildNodes, result.Add, partId);

			return result;
		}

		public override void ReqursiveScanNodesByPartId(HtmlNodeCollection nodeCollection, Action<HtmlNode> findNodeAction,
			string partId)
		{
			if (nodeCollection == null || findNodeAction == null || string.IsNullOrWhiteSpace(partId))
				return;

			nodeCollection
				.Where(el => el.Id != null && el.Id.StartsWith(partId))
				.ToList()
				.ForEach(findNodeAction);

			foreach (var node in nodeCollection.Where(node => node.ChildNodes != null))
			{
				ReqursiveScanNodesByPartId(node.ChildNodes, findNodeAction, partId);
			}
		}

		public override IEnumerable<HtmlNode> FindNodesByAttributeValue(HtmlNode htmlNode, string attributeName, string attributeValue, bool isPartValue = false,
			IEnumerable<string> badPartValues = null)
		{
			if (htmlNode == null) return null;

			var result = new List<HtmlNode>();

			ReqursiveScanNodesByAttributeValue(htmlNode.ChildNodes, result.Add, attributeName, attributeValue, isPartValue, badPartValues);

			return result;
		}

		public override void ReqursiveScanNodesByAttributeValue(HtmlNodeCollection nodeCollection, Action<HtmlNode> findNodeAction, string attributeName,
			string attributeValue, bool isPartValue = false, IEnumerable<string> badPartValues = null)
		{
			if (nodeCollection == null || findNodeAction == null
				|| string.IsNullOrWhiteSpace(attributeName) || string.IsNullOrWhiteSpace(attributeValue))
				return;

			nodeCollection
				.Where(el => el.Attributes[attributeName] != null
					&&
					(!isPartValue
						? el.Attributes[attributeName].Value.Trim().Equals(attributeValue.Trim())
						: el.Attributes[attributeName].Value.Trim().Contains(attributeValue.Trim()) && (badPartValues == null || !badPartValues.Any(bpv => el.Attributes[attributeName].Value.Trim().Contains(bpv)))))
				.ToList()
				.ForEach(findNodeAction);

			foreach (var node in nodeCollection.Where(node => node.ChildNodes != null))
			{
				ReqursiveScanNodesByAttributeValue(node.ChildNodes, findNodeAction, attributeName, attributeValue, isPartValue, badPartValues);
			}
		}

		public override DateTime GetInnerTextDateTime(HtmlNode htmlNode)
		{
			if (htmlNode == null) return default(DateTime);

			var text = HttpUtility.HtmlDecode(GetFullInnerTextString(htmlNode));
			if (string.IsNullOrWhiteSpace(text)) return default(DateTime);

			var nums = text.Split(new[] {GC_FFW.Common.Constants.Text.Symbols.SLASH}, StringSplitOptions.RemoveEmptyEntries);

			int num;

			var day = nums.Any() && int.TryParse(nums.ElementAt(0), out num) ? num : DateTime.Now.Day;
			var month = nums.Count() > 1 && int.TryParse(nums.ElementAt(1), out num) ? num : DateTime.Now.Month;
			var year = nums.Count() > 2 && int.TryParse(nums.ElementAt(2), out num) ? num : DateTime.Now.Year;

			var result = new DateTime(year, month, day);
			if (result > DateTime.Now)
				result = result.AddYears(-1);

			return result;
		}

		public override int GetInnerTextInt(HtmlNode htmlNode)
		{
			if (htmlNode == null) return default(int);

			int value;
			int.TryParse(GetFullInnerTextString(htmlNode), out value);
			return value;
		}

		#endregion
	}
}
